﻿using UnityEngine;
using System.Collections;

public class GameBoard : MonoBehaviour {

	public GameHex hexPrefab;
	
	public int boardSize;
	public Vector2 offsetRight;
	
	private Matrix4x4 matGameToWorld;
	private Vector2[] neighbourOffsets;
	
	private Transform[][] cells;
	
	// Use this for initialization
	void Awake () {
		matGameToWorld = new Matrix4x4 ();
		matGameToWorld.SetColumn (0, new Vector4( offsetRight.y, -offsetRight.x, 0.0f, 0.0f) );
		matGameToWorld.SetColumn (1, new Vector4( offsetRight.x, -offsetRight.y, 1.0f, 0.0f) );
		matGameToWorld.SetColumn (2, new Vector4( 0.0f, 0.0f, 1.0f, 0.0f) );
		matGameToWorld.SetColumn (3, new Vector4( 0.0f, 0.0f, 0.0f, 1.0f) );
		
		neighbourOffsets = new Vector2[6];
		neighbourOffsets [0] = new Vector2 (1,0); //side:1
		neighbourOffsets [1] = new Vector2 (0,1); //side:1
		neighbourOffsets [2] = new Vector2 (-1,1); //side:2
		neighbourOffsets [3] = new Vector2 (-1,0); //side:2
		neighbourOffsets [4] = new Vector2 (0,-1); //side:3
		neighbourOffsets [5] = new Vector2 (1,-1); //side:3
	}

	// Update is called once per frame
	void Update () {
		//
	}

	void Save() {
		//
	}

	public void Clear() {
		if (cells != null) {
			for (int x = 0; x < boardSize; x++) {
				for (int y = 0; y < boardSize; y++) {
					//if (cells[x][y] != null) {
					Destroy( cells[x][y].gameObject );
					//cells[x][y] = null;
					//}
				}
			}
		}
	}

	public void Load() {
		Clear();
		
		cells = new Transform[boardSize][];
		for (int x = 0; x < boardSize; x++) {
			cells[x] = new Transform[boardSize];
			for (int y = 0; y < boardSize; y++) {
				Transform hexTransform = CreateHex (new Vector2(x,y));
				hexTransform.GetComponent<GameHex>().clear();
				
				Vector3 position = hexTransform.position;
				position.y = 0.05f;
				hexTransform.position = position;
				
				hexTransform.renderer.material.color = Color.green;
				cells[x][y] = hexTransform;
			}
		}
	}
	
	// Hex management
	public Transform CreateHex( Vector2 gamePos ) {
		GameObject hexObject = (GameObject)Instantiate( hexPrefab.gameObject );
		hexObject.transform.localPosition = gameToWorldPos( gamePos );
		return hexObject.transform;
	}
	
	public void MoveHex( Transform hexTransform, Vector2 gamePos ) {
		hexTransform.localPosition = gameToWorldPos( gamePos );
	}

	public Transform CreateEffect( Vector2 gamePos, Transform prefab ) {
		GameObject effectObj = (GameObject)Instantiate( prefab.gameObject );
		effectObj.transform.localPosition = gameToWorldPos( gamePos );
		return effectObj.transform;
	}

	public void SetCellVisible( Vector2 gamePos, bool visible ) {
		if (IsValidPosition( gamePos )) {
			int x = Mathf.FloorToInt(gamePos.x);
			int y = Mathf.FloorToInt(gamePos.y);
			cells[x][y].renderer.enabled = visible;
		}
	}

	public void SetCellVisible( int cellIndex, bool visible ) {
		int x = cellIndex / boardSize;
		int y = cellIndex % boardSize;
		cells[x][y].renderer.enabled = visible;
	}
	
	public void SetCellLocked( Vector2 gamePos, bool locked ) {
		if (IsValidPosition( gamePos )) {
			int x = Mathf.FloorToInt(gamePos.x);
			int y = Mathf.FloorToInt(gamePos.y);
			cells[x][y].renderer.material.color = locked ? Color.red : Color.green;
		}
	}
	
	public void SetCellLocked( int cellIndex, bool locked ) {
		int x = cellIndex / boardSize;
		int y = cellIndex % boardSize;
		cells[x][y].renderer.material.color = locked ? Color.red : Color.green;
	}
	
	public bool GetTouchInput( out Vector2 gamePos ) {
		Vector2 touchPos;
		gamePos = new Vector2();
		#if UNITY_EDITOR || UNITY_STANDALONE_WIN
		if (Input.GetMouseButtonDown (0)) {
			touchPos = Input.mousePosition;
		#else
		if (Input.touchCount > 0 &&
		    Input.GetTouch(0).phase == TouchPhase.Began) {
			touchPos = Input.GetTouch(0).position;
		#endif
			Debug.Log("GameManager.Update : touchPos=" + touchPos);
			//get the projected position on the ground
			Ray ray = Camera.main.ScreenPointToRay(touchPos);
			RaycastHit hitInfo;
			if (Physics.Raycast(ray, out hitInfo)) {
				//Debug.Log ("GameManager.Update : TODO click on board!");
				
				// determine the slot in the board from the clicked point
				gamePos = worldToGamePos( hitInfo.point );
				if (IsValidPosition(gamePos))
					return true;
			}
		}
		
		return false;
	}
	
	public bool IsValidPosition( Vector2 gamePos ) {
		return (gamePos.x >= 0 && gamePos.x < boardSize && gamePos.y >= 0 && gamePos.y < boardSize);
	}
	
	public int GetCellIndex( Vector2 gamePos ) {
		return Mathf.FloorToInt(gamePos.x) * boardSize + Mathf.FloorToInt(gamePos.y);
	}

	// coordinate conversion
	Vector2 worldToGamePos(Vector3 worldPos) {
		// convert from world to game coordinates
		Vector3 gamePos = matGameToWorld.inverse.MultiplyPoint ( new Vector3(worldPos.x, worldPos.z, 0.0f) );
		return new Vector2( Mathf.Floor( gamePos.x + 0.5f ), Mathf.Floor( gamePos.y + 0.5f ) );
	}
	
	Vector3 gameToWorldPos(Vector2 gamePos) {
		// convert board coordinates to world
		Vector3 worldPos = matGameToWorld.MultiplyPoint (new Vector3 (gamePos.x, gamePos.y, 0.0f));
		worldPos = new Vector3 (worldPos.x, 0.1f, worldPos.y);
		return worldPos;
	}
}
